package vip.lsjscl.flowboot.workflow.service;

import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import vip.lsjscl.flowboot.common.BusinessException;
import vip.lsjscl.flowboot.util.constants.TaskDecision;
import vip.lsjscl.flowboot.workflow.entity.DKActivity;
import vip.lsjscl.flowboot.workflow.entity.DKRuntimeTask;
import vip.lsjscl.flowboot.workflow.entity.DKWorkflow;
import vip.lsjscl.flowboot.workflow.entity.DKWorkflowVersion;
import vip.lsjscl.flowboot.workflow.model.FlowDiagram;
import vip.lsjscl.flowboot.workflow.model.dto.ProcessDataDto;
import vip.lsjscl.flowboot.workflow.model.dto.WorkflowCreateDTO;
import vip.lsjscl.flowboot.workflow.repository.DKWorkflowRepository;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 工作流服务实现类
 * 提供工作流的创建、更新、发布、查询等核心功能
 *
 * @author zhangxingju
 * @date 2025/02/13
 */
@Transactional(rollbackFor = Exception.class)
@Service
@RequiredArgsConstructor
public class DKWorkflowService {
    private static final Logger log = LoggerFactory.getLogger(DKWorkflowService.class);

    private final DKWorkflowRepository workflowRepository;
    private final DKWorkflowVersionService workflowVersionService;
    private final DKTransitionService transitionService;
    private final DKActivityService activityService;
    private final DKRuntimeTaskService runtimeTaskService;

    /**
     * 启动工作流
     * 根据工作流编码创建新的工作流实例并启动第一个活动节点
     *
     * @param workflowCode 工作流编码
     * @param businessId   业务ID，关联外部系统业务数据
     * @return 工作流版本ID
     * @throws BusinessException 如果工作流不存在或未发布
     */
    public String startWorkflow(String workflowCode, String businessId) {
        Long initialized = activityService.isProcessInitialized(businessId);
        if (initialized > 0) {
            throw new BusinessException("流程已被初始化,请检查");
        }


        log.debug("开始启动工作流, workflowCode: {}, businessId: {}", workflowCode, businessId);
        // 获取最新版本的工作流
        DKWorkflowVersion latestVersion = workflowVersionService.getLatestWorkflowVersion(workflowCode);
        // 初始化活动节点
        ((DKWorkflowService) AopContext.currentProxy()).initializeActivities(latestVersion, businessId);

        // 获取开始节点
        DKActivity startActivity = activityService.getStartActivity(latestVersion.getId(), businessId);

        // 获取第一个活动节点
        List<DKActivity> nextActivities = activityService.getNextActivity(startActivity);
        if (CollectionUtils.isEmpty(nextActivities)) {
            throw new BusinessException("未找到第一个活动节点");
        }
        DKActivity firstActivity = nextActivities.get(0);

        // 激活第一个节点和下一个节点
        activityService.activateStartNodeAndTransition(firstActivity);

        log.debug("工作流启动成功, versionId: {}", latestVersion.getId());
        return latestVersion.getId();
    }


    /**
     * 重新提交的方法
     *
     * @param businessId           业务 ID
     * @param activityCode         发起申请的活动code
     * @param goBackToFallbackNode 是否直接到回退节点,如果为true，则直接到回退节点
     */
    public void resubmit(String businessId, String activityCode, boolean goBackToFallbackNode) {
        //获取任务id
        List<DKRuntimeTask> todoTasks = runtimeTaskService.getTodoTasksByActivityCode(businessId, activityCode);
        if (CollectionUtils.isEmpty(todoTasks)) {
            throw new BusinessException("未查询到你的退回办件,请退出重试");
        }
        ProcessDataDto processDataDto = new ProcessDataDto();
        processDataDto.setId(todoTasks.get(0).getId());
        processDataDto.setComment("重新提交");
        processDataDto.setBusinessId(businessId);
        processDataDto.setAction(TaskDecision.APPROVED);
        //如果为true，则直接到回退节点
        if (goBackToFallbackNode) {
            DKActivity returnActivity = activityService.getReturnActivity(businessId);
            processDataDto.setNextNodeId(returnActivity.getId());
        }
        activityService.updateCurrentTaskActivity(processDataDto);
    }

    /**
     * 初始化活动节点和变迁
     */
    public void initializeActivities(DKWorkflowVersion version, String businessId) {
        Map<String, DKActivity> activityMap = new HashMap<>();
        FlowDiagram flowDiagram = version.getFlowData();
        // 创建活动节点
        if (flowDiagram.getNodes() != null) {
            flowDiagram.getNodes().forEach(node -> activityService.createActivity(node, version, businessId, activityMap));
        }
        // 创建变迁关系
        if (flowDiagram.getEdges() != null) {
            flowDiagram.getEdges().forEach(edge -> transitionService.createTransition(edge, version, businessId, activityMap));
        }
    }


    public DKWorkflow createWorkflow(WorkflowCreateDTO dto) {
        // 检查工作流编码是否已存在
        if (workflowRepository.existsByCode(dto.getCode())) {
            throw new BusinessException("工作流编码已存在");
        }
        DKWorkflow workflow = new DKWorkflow();
        workflow.setName(dto.getName());
        workflow.setCode(dto.getCode());
        workflow.setCreateTime(LocalDateTime.now());
        workflow.setStatus(0);
        workflow.setFlowData(null);
        if (dto.getFlowData() != null) {
            workflow.setFlowData(dto.getFlowData());
        }
        return workflowRepository.save(workflow);
    }

    public DKWorkflow saveWorkflow(FlowDiagram flowData, String id) {
        DKWorkflow workflow;
        if (id != null) {
            workflow = workflowRepository.findById(id).orElseThrow(() -> new BusinessException("工作流不存在"));
        }
        else {
            workflow = new DKWorkflow();
        }
        workflow.setFlowData(flowData);
        return workflowRepository.save(workflow);
    }

    public DKWorkflow findById(String id) {
        return workflowRepository.findById(id).orElseThrow(() -> new BusinessException("工作流不存在"));
    }

    /**
     * 删除未发布的工作流
     *
     * @param id 工作流ID
     */
    public void deleteWorkflow(String id) {
        DKWorkflow workflow = workflowRepository.findById(id).orElseThrow(() -> new BusinessException("工作流不存在"));

        // 检查工作流状态，只能删除未发布的工作流
        if (workflow.getStatus() == 1) {
            throw new BusinessException("已发布的工作流不能删除");
        }

        // 删除工作流
        workflowRepository.deleteById(id);
    }
}